﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Pavilion;
using Microsoft.Xna.Framework.Graphics;
using System.Reflection;
using System.Diagnostics;
using Pavilion.GameTools;
using System.Collections;

namespace Pavilion.Communications
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class UpdateGameService : IUpdateGameService, ITransferringService
    {
        public bool IsTransferring { get; private set; }

        private string TryExecute(Action action, string errorMessage)
        {
            try { action.Invoke(); }
            catch (Exception ex) { return errorMessage + Environment.NewLine + ObtainExceptionDetails(ex); }

            return "";
        }

        private string ObtainExceptionDetails(Exception ex)
        {
            string message = "MainException: " + ex.Message;

            while (ex.InnerException != null)
            {
                ex = ex.InnerException;
                message += Environment.NewLine + "Inner Exception: " + ex.Message;
            }

            return message;
        }

        public void BeginDataTransfer()
        {
            IsTransferring = true;
            Pavilion.GameTools.AnimationTool.PauseAnimationTools();
        }

        public void EndDataTransfer()
        {
            IsTransferring = false;
            Pavilion.GameTools.AnimationTool.ResumeAnimationTools();
        }

        public string RenameAnimation(string resourceName, string oldName, string newName)
        {
            return TryExecute(() => 
                {
                    ResourceManager.Instance[resourceName].ObtainResourceCollection<AnimationCollection>()[oldName].Name = newName;
                },
                "RenameAnimation Failed. resourceName=" + resourceName + ", oldName=" + oldName + ", newName=" + newName);
        }

        public string InsertAnimation(string resourceName, string animationName)
        {
            return TryExecute(() => 
                {
                    ResourceManager.Instance[resourceName].ObtainResourceCollection<AnimationCollection>().AddAnimation(new Animation { Name = animationName });
                },
                "InsertAnimation Failed. resourceName=" + resourceName + ", animationName=" + animationName);
        }

        public string RemoveAnimation(string resourceName, string animationName)
        {
            return TryExecute(() => 
                {
                    ResourceManager.Instance[resourceName].ObtainResourceCollection<AnimationCollection>().RemoveAnimation(animationName);
                },
                "RemoveAnimation Failed. resourceName=" + resourceName + ", animationName=" + animationName);
        }

        public string UpdateFrameOrigin(string resourceName, string animationName, int frameIndex, float originX, float originY)
        {
            return TryExecute(() =>
                {
                    Frame frame = ResourceManager.Instance[resourceName].ObtainResourceCollection<AnimationCollection>()[animationName].FrameList[frameIndex];

                    frame.OriginX = originX;
                    frame.OriginY = originY;
                },
                "UpdateFrameOrigin Failed. resourceName=" + resourceName + ", animationName=" + animationName + ", frameIndex=" + frameIndex + ", originX=" + originX + ", originY=" + originY);
        }

        public string ReorderFrame(string resourceName, string animationName, int oldIndex, int newIndex)
        {
            return TryExecute(() =>
                {
                    ResourceManager.Instance[resourceName].ObtainResourceCollection<AnimationCollection>()[animationName].FrameList.Move(oldIndex, newIndex);
                },
                "ReorderFrame Failed.");
        }

        public string RemoveFrame(string resourceName, string animationName, int frameIndex)
        {
            return TryExecute(() =>
                {
                    ResourceManager.Instance[resourceName].ObtainResourceCollection<AnimationCollection>()[animationName].FrameList.RemoveAt(frameIndex);
                },
                "RemoveFrame Failed.");
        }

        public string InsertFrame(string resourceName, string animationName, int frameIndex)
        {
            return TryExecute(() =>
                {
                    Animation animation = ResourceManager.Instance[resourceName].ObtainResourceCollection<AnimationCollection>()[animationName];

                    animation.FrameList.Insert(frameIndex, animation.CreateDefaultFrame());
                },
                "InsertFrame Failed.");
        }

        public string UpdateTextureVisibility(string resourceName, string animationName, int frameIndex, int textureIndex, bool isVisible)
        {
            return TryExecute(() =>
                {
                    ResourceManager.Instance[resourceName].ObtainResourceCollection<AnimationCollection>()[animationName].FrameList[frameIndex].TextureList[textureIndex].Visible = isVisible;
                },
                "UpdateTextureVisibility Failed.");
        }

        public string ReorderTexture(string resourceName, string animationName, int frameIndex, int oldIndex, int newIndex)
        {
            return TryExecute(() =>
                {
                    ResourceManager.Instance[resourceName].ObtainResourceCollection<AnimationCollection>()[animationName].FrameList[frameIndex].TextureList.Move(oldIndex, newIndex);
                },
                "ReorderTexture Failed.");
        }

        public string RemoveTexture(string resourceName, string animationName, int frameIndex, int textureIndex)
        {
            return TryExecute(() =>
                {
                    ResourceManager.Instance[resourceName].ObtainResourceCollection<AnimationCollection>()[animationName].FrameList[frameIndex].TextureList.RemoveAt(textureIndex);
                },
                "RemoveTexture Failed.");
        }

        public string InsertTexture(string resourceName, string animationName, int frameIndex, int textureIndex, byte[] textureData, int textureWidth, int textureHeight)
        {
            return TryExecute(() =>
                {
                    Texture2D texture = CTexture2D.CreateTexture(textureWidth, textureHeight);
                    texture.SetData<byte>(textureData);

                    ResourceManager.Instance[resourceName].ObtainResourceCollection<AnimationCollection>()[animationName].FrameList[frameIndex].TextureList.Insert(textureIndex, new CTexture2D(texture));
                },
                "InsertTexture Failed.");
        }

        public string UpdateTexture(string resourceName, string animationName, int frameIndex, int textureIndex, byte[] textureData, int textureWidth, int textureHeight)
        {
            return TryExecute(() =>
                {
                    Texture2D texture = CTexture2D.CreateTexture(textureWidth, textureHeight, textureData);

                    ResourceManager.Instance[resourceName].ObtainResourceCollection<AnimationCollection>()[animationName].FrameList[frameIndex].TextureList[textureIndex].TextureItem = texture;
                },
                "UpdateTexture Failed.");
        }

        public string UpdateLockData(string resourceName, string scriptName, List<string> containerNodeNameList, int linkIndex, int lockIndex, string propertyName, string propertyValue, string fullAssemblyName, string propertyTypeName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);
                    ILock lockItem = containerNode.LinkCollection[linkIndex].GetLock(lockIndex);

                    object objectValue = null;
                    if (propertyTypeName == typeof(GameItem).FullName)
                    {
                        if (!string.IsNullOrEmpty(propertyValue))
                            objectValue = GameItemManager.Instance[propertyValue];
                    }
                    else
                    {
                        objectValue = GameEngine.CreateInstance<object>(fullAssemblyName, propertyTypeName);
                        objectValue = GameEngine.ParseObject(objectValue.GetType(), propertyValue);
                    }

                    lockItem.GetType().GetProperty(propertyName).SetValue(lockItem, objectValue, null);
                },
                "UpdateLockData Failed.");
        }

        public string AddLock(string resourceName, string scriptName, List<string> containerNodeNameList, int linkIndex, string fullAssemblyName, string propertyTypeName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);
                    object objectValue = GameEngine.CreateInstance<object>(fullAssemblyName, propertyTypeName);

                    containerNode.LinkCollection[linkIndex].AddLock(objectValue as ILock);
                },
                "AddLock Failed.");
        }

        public string RemoveLock(string resourceName, string scriptName, List<string> containerNodeNameList, int linkIndex, int lockIndex)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);
                    containerNode.LinkCollection[linkIndex].RemoveLockAt(lockIndex);
                },
                "RemoveLock Failed.");
        }

        public string AddLink(string resourceName, string scriptName, List<string> containerNodeNameList, string startNodeName, string endNodeName, string openCriteria)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);
                    OpenCriteria openCriteriaEnum = (OpenCriteria)Enum.Parse(typeof(OpenCriteria), openCriteria);

                    containerNode.LinkNode(containerNode[startNodeName], containerNode[endNodeName], null, openCriteriaEnum);
                },
                "AddLink Failed.");
        }

        public string RemoveLink(string resourceName, string scriptName, List<string> containerNodeNameList, int linkIndex)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);

                    containerNode.LinkCollection[linkIndex].Dispose();
                },
                "RemoveLink Failed.");
        }

        public string UpdateLinkOpenCriteria(string resourceName, string scriptName, List<string> containerNodeNameList, int linkIndex, string openCriteria)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);

                    containerNode.LinkCollection[linkIndex].OpenCriteria = (OpenCriteria)Enum.Parse(typeof(OpenCriteria), openCriteria);
                },
                "UpdateLinkOpenCriteria Failed.");
        }

        public string AddNode(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string nodeType)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);

                    if (typeof(ContainerNode).Name == nodeType)
                        containerNode.AddNode(new ContainerNode(nodeName));
                    else
                        containerNode.AddNode(new AnimationNode(nodeName));
                },
                "AddNode Failed.");
        }

        public string RemoveNode(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);

                    containerNode.RemoveNode(nodeName);
                },
                "RemoveNode Failed.");
        }

        public string RenameNode(string resourceName, string scriptName, List<string> containerNodeNameList, string oldName, string newName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);

                    if (containerNode.Contains(oldName))
                        containerNode[oldName].Name = newName;
                },
                "RenameNode Failed.");
        }

        public string UpdateAnimationNode(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string animationName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);

                    (containerNode[nodeName] as AnimationNode).Animation = ResourceManager.Instance[resourceName].ObtainResourceCollection<AnimationCollection>()[animationName];
                    UpdateAllCurrentAnimations();
                },
                "UpdateAnimationNode Failed.");
        }

        public string AddGameDataProperty(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, int gameDataIndex, string propertyName, string propertyValue, string fullAssemblyName, string propertyTypeName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);
                    object objectValue = GameEngine.CreateInstance<object>(fullAssemblyName, propertyTypeName);
                    objectValue = GameEngine.CreateInstance<object>(fullAssemblyName, propertyTypeName);

                    containerNode[nodeName].GameDataCollection[gameDataIndex].AddData(propertyName, GameEngine.ParseObject(objectValue.GetType(), propertyValue));
                    UpdateGameDataOfNode(containerNode[nodeName]);
                },
                "AddGameDataProperty Failed.");
        }

        public string RemoveGameDataProperty(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, int gameDataIndex, string propertyName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);

                    containerNode[nodeName].GameDataCollection[gameDataIndex].RemoveData(propertyName);
                    UpdateGameDataOfNode(containerNode[nodeName]);
                },
                "RemoveGameDataProperty Failed.");
        }

        public string UpdateGameDataGameItemName(string gameItemName, string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, int gameDataIndex)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);
                    containerNode[nodeName].GameDataCollection[gameDataIndex].GameItemName = gameItemName;

                    UpdateGameDataOfNode(containerNode[nodeName]);
                },
                "UpdateGameDataGameItemName Failed.");
        }

        public string UpdateGameData(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, int gameDataIndex, string propertyName, string propertyValue, string fullAssemblyName, string propertyTypeName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);
                    object objectValue = GameEngine.CreateInstance<object>(fullAssemblyName, propertyTypeName);

                    containerNode[nodeName].GameDataCollection[gameDataIndex].PropertyDictionary[propertyName] = GameEngine.ParseObject(objectValue.GetType(), propertyValue);
                    UpdateGameDataOfNode(containerNode[nodeName]);
                },
                "UpdateGameData Failed.");
        }

        public string AddGameData(string gameItemName, string gameToolName, string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string fullAssemblyName, string gameDataTypeName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);

                    containerNode[nodeName].GameDataCollection.Add(new GameData() { GameItemName = gameItemName, GameToolName = gameToolName });
                    UpdateGameDataOfNode(containerNode[nodeName]); 
                },
                "AddGameData Failed.");
        }

        public string RemoveGameData(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, int gameDataIndex)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);

                    containerNode[nodeName].GameDataCollection.RemoveAt(gameDataIndex);
                    UpdateGameDataOfNode(containerNode[nodeName]);
                },
                "RemoveGameData Failed.");
        }

        public string AddResourceItem(string resourceName)
        {
            return TryExecute(() =>
                {
                    ResourceManager.Instance.AddResourceItem(new ResourceItem(resourceName));
                },
                "AddResourceItem Failed.");
        }

        public string RemoveResourceItem(string resourceName)
        {
            return TryExecute(() =>
                {
                    if (ResourceManager.Instance.Contains(resourceName))
                    {
                        ResourceItem resourceItem = ResourceManager.Instance[resourceName];

                        ResourceManager.Instance.RemoveResource(resourceName);
                        resourceItem.Dispose();
                    }
                },
                "RemoveResourceItem Failed.");
        }

        public string RenameResource(string oldResourceName, string newResourceName)
        {
            return TryExecute(() =>
                {
                    if (ResourceManager.Instance.Contains(oldResourceName))
                        ResourceManager.Instance[oldResourceName].Name = newResourceName;
                },
                "RenameResource Failed.");
        }

        public string AddNodeScript(string resourceName, string scriptName)
        {
            return TryExecute(() =>
                {
                    ResourceManager.Instance[resourceName].ObtainResourceCollection<NodeScriptCollection>().AddNodeScript(new NodeScript(scriptName));
                },
                "AddNodeScript Failed.");
        }

        public string RemoveNodeScript(string resourceName, string scriptName)
        {
            return TryExecute(() =>
                {
                    ResourceManager.Instance[resourceName].ObtainResourceCollection<NodeScriptCollection>().RemoveNodeScript(scriptName); 
                },
                "RemoveNodeScript Failed.");
        }

        public string RenameNodeScript(string resourceName, string oldName, string newName)
        {
            return TryExecute(() =>
                {
                    ResourceManager.Instance[resourceName].ObtainResourceCollection<NodeScriptCollection>().GetNodeScript(oldName).Name = newName;
                },
                "RenameNodeScript Failed.");
        }

        public string AddGameItem(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string gameItemName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);
                    LoadNode loadNode = containerNode[nodeName] as LoadNode;
                    loadNode.AddGameItem(gameItemName);

                    if (IsNodeCurrentlyRunning(loadNode))
                        loadNode.LoadGameItem(gameItemName);
                },
                "AddGameItem Failed.");
        }

        public string RemoveGameItem(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string gameItemName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);
                    (containerNode[nodeName] as LoadNode).RemoveGameItem(gameItemName);

                    if (GameItemManager.Instance.Contains(gameItemName))
                        GameItemManager.Instance.UnloadGameItem(gameItemName);
                },
                "RemoveGameItem Failed.");
        }
        
        public string RenameGameItem(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string oldGameItemName, string newGameItemName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);
                    (containerNode[nodeName] as LoadNode).RenameGameItem(oldGameItemName, newGameItemName);

                },
                "RenameGameItem Failed.");
        }

        public string AddGameTool(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string gameItemName, string gameToolName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);
                    (containerNode[nodeName] as LoadNode).AddGameTool(gameItemName, gameToolName);
                },
                "AddGameTool Failed.");
        }

        public string RemoveGameTool(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string gameItemName, string gameToolName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);
                    (containerNode[nodeName] as LoadNode).RemoveGameTool(gameItemName, gameToolName);
                },
                "RemoveGameTool Failed.");
        }

        public string AddGameToolDataProperty(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string gameItemName, string gameToolName, string propertyName, string propertyValue, string fullAssemblyName, string propertyTypeName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);
                    object objectValue = GameEngine.CreateInstance<object>(fullAssemblyName, propertyTypeName);
                    objectValue = GameEngine.CreateInstance<object>(fullAssemblyName, propertyTypeName);
                    LoadNode loadNode = containerNode[nodeName] as LoadNode;
                    GameData gameData = loadNode.ObtainGameData(gameItemName, gameToolName);

                    gameData.AddData(propertyName, GameEngine.ParseObject(objectValue.GetType(), propertyValue));

                    if (IsNodeCurrentlyRunning(loadNode))
                        gameData.UpdateProperty(null, propertyName);
                },
                "AddGameToolDataProperty Failed.");
        }

        public string RemoveGameToolDataProperty(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string gameItemName, string gameToolName, string propertyName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);

                    (containerNode[nodeName] as LoadNode).ObtainGameData(gameItemName, gameToolName).RemoveData(propertyName);
                },
                "RemoveGameToolDataProperty Failed.");
        }

        public string UpdateGameToolDataProperty(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string gameItemName, string gameToolName, string propertyName, string propertyValue, string fullAssemblyName, string propertyTypeName)
        {
            return TryExecute(() =>
                {
                    ContainerNode containerNode = (ContainerNode)ObtainNodeFromList(containerNodeNameList, resourceName, scriptName);
                    object objectValue = GameEngine.CreateInstance<object>(fullAssemblyName, propertyTypeName);
                    objectValue = GameEngine.CreateInstance<object>(fullAssemblyName, propertyTypeName);
                    LoadNode loadNode = containerNode[nodeName] as LoadNode;
                    GameData gameData = loadNode.ObtainGameData(gameItemName, gameToolName);
                    object newValue = GameEngine.ParseObject(objectValue.GetType(), propertyValue);

                    if (!CompareObjects(gameData.PropertyDictionary[propertyName], newValue))
                    {
                        gameData.PropertyDictionary[propertyName] = newValue;

                        if (IsNodeCurrentlyRunning(loadNode))
                            gameData.UpdateProperty(null, propertyName);
                    }
                },
                "UpdateGameToolDataProperty Failed.");
        }

        public void RequestUpdateForLoadedNodes()
        {
            System.Threading.Tasks.Task.Factory.StartNew(() =>
            {
                IEnumerable<NodeTool> nodeToolList = GameItemManager.Instance.GameItemCollection
                            .Where(x => x.ContainsTool<NodeTool>())
                            .Select(x => x.ObtainTool<NodeTool>());

                foreach (NodeTool nodeTool in nodeToolList)
                {
                    foreach (ContainerNodeMonitor containerNodeMonitor in nodeTool.ContainerNodeMonitorCollection.Values)
                    {
                        ContainerNodeMonitor curentContainerNodeMonitor = containerNodeMonitor;
                        NodeBase currentNode = curentContainerNodeMonitor.CurrentNode;

                        while (currentNode != null)
                        {
                            NodeScript nodeScript = curentContainerNodeMonitor.ParentNodeScript;
                            ResourceItem resource = ResourceManager.Instance.ResourceCollection.First(x => x.ObtainResourceCollection<NodeScriptCollection>().Contains(nodeScript));
                            DesignerClient.Instance.Proxy.NodeLoaded(resource.Name, nodeScript.Name, UpdateGameService.CreateNodeStringCollection(currentNode.ParentContainer), currentNode.Name);

                            if (currentNode is ContainerNode)
                            {
                                curentContainerNodeMonitor = curentContainerNodeMonitor.CurrentContainerNodeMonitor;
                                currentNode = curentContainerNodeMonitor.CurrentNode;
                            }
                            else
                                currentNode = null;
                        }
                    }
                }
            });
        }

        static public ContainerNode ObtainNodeFromList(List<string> containerNodeNameList, string resourceName, string scriptName)
        {
            ContainerNode containerNode = ResourceManager.Instance[resourceName].ObtainResourceCollection<NodeScriptCollection>().GetNodeScript(scriptName).RootContainer;

            for (int i = 1; i < containerNodeNameList.Count; i++)//Skips the Root Container
            {
                NodeBase nodeBase = containerNode[containerNodeNameList[i]];
                if (nodeBase is ContainerNode)
                    containerNode = (ContainerNode)nodeBase;
            }

            return containerNode;
        }

        static public List<string> CreateNodeStringCollection(ContainerNode containerNode)
        {
            List<string> containerNodeNameList = new List<string>();

            while (containerNode != null)
            {
                containerNodeNameList.Insert(0, containerNode.Name);
                containerNode = containerNode.ParentContainer;
            }

            return containerNodeNameList;
        }

        private void UpdateLockMontior(ILock lockItem)
        {
            foreach (NodeTool nodeTool in GameItemManager.Instance.GetToolsFromGameItems<NodeTool>())
            {
                foreach (ContainerNodeMonitor nodeMonitor in nodeTool.ContainerNodeMonitorCollection.Values)
                    nodeMonitor.UpdateLockMontior(lockItem);
            }
        }

        private void UpdateGameDataOfNode(NodeBase nodeBase)
        {
            foreach (NodeTool nodeTool in GameItemManager.Instance.GetToolsFromGameItems<NodeTool>())
            {
                foreach (ContainerNodeMonitor nodeMonitor in nodeTool.ContainerNodeMonitorCollection.Values)
                    nodeMonitor.UpdateGameDataOfNode(nodeBase);
            }
        }

        private bool IsNodeCurrentlyRunning(NodeBase nodebase)
        {
            foreach (NodeTool nodeTool in GameItemManager.Instance.GetToolsFromGameItems<NodeTool>())
            {
                foreach (ContainerNodeMonitor nodeMonitor in nodeTool.ContainerNodeMonitorCollection.Values)
                {
                    if (nodeMonitor.IsCurrentNode(nodebase))
                        return true;
                }
            }

            return false;
        }

        private void UpdateAllCurrentAnimations()
        {
            foreach (AnimationTool animationTool in GameItemManager.Instance.GetToolsFromGameItems<Pavilion.GameTools.AnimationTool>())
                animationTool.UpdateCurrentAnimation();
        }

        private bool CompareObjects(object value1, object value2)
        {
            if (value1 is IEnumerable && value2 is IEnumerable)
            {
                IEnumerator enumerator1 = (value1 as IEnumerable).GetEnumerator();
                IEnumerator enumerator2 = (value2 as IEnumerable).GetEnumerator();

                bool hasMore1 = enumerator1.MoveNext();
                bool hasMore2 = enumerator2.MoveNext();

                while (hasMore1 && hasMore2)
                {
                    if (!CompareObjects(enumerator1.Current, enumerator2.Current))
                        return false;

                    hasMore1 = enumerator1.MoveNext();
                    hasMore2 = enumerator2.MoveNext();
                }

                if (hasMore1 != hasMore2)
                    return false;

                return true;
            }

            if (value1 == null)
                return false;

            return value1.Equals(value2);
        }
    }

    [ServiceContract()]
    public interface IUpdateGameService
    {
        [OperationContract]
        void BeginDataTransfer();
        [OperationContract]
        void EndDataTransfer();
        [OperationContract]
        string UpdateFrameOrigin(string resourceName, string animationName, int frameIndex, float originX, float originY);
        [OperationContract]
        string ReorderFrame(string resourceName, string animationName, int oldIndex, int newIndex);
        [OperationContract]
        string RemoveFrame(string resourceName, string animationName, int frameIndex);
        [OperationContract]
        string InsertFrame(string resourceName, string animationName, int frameIndex);
        [OperationContract]
        string UpdateTextureVisibility(string resourceName, string animationName, int frameIndex, int textureIndex, bool isVisible);
        [OperationContract]
        string ReorderTexture(string resourceName, string animationName, int frameIndex, int oldIndex, int newIndex);
        [OperationContract]
        string RemoveTexture(string resourceName, string animationName, int frameIndex, int textureIndex);
        [OperationContract]
        string InsertTexture(string resourceName, string animationName, int frameIndex, int textureIndex, byte[] textureData, int textureWidth, int textureHeight);
        [OperationContract]
        string UpdateTexture(string resourceName, string animationName, int frameIndex, int textureIndex, byte[] textureData, int textureWidth, int textureHeight);
        [OperationContract]
        string InsertAnimation(string resourceName, string animationName);
        [OperationContract]
        string RemoveAnimation(string resourceName, string animationName);
        [OperationContract]
        string RenameAnimation(string resourceName, string oldName, string newName);
        [OperationContract]
        string UpdateLockData(string resourceName, string scriptName, List<string> containerNodeList, int linkIndex, int lockIndex, string propertyName, string propertyValue, string fullAssemblyName, string propertyTypeName);
        [OperationContract]
        string AddLock(string resourceName, string scriptName, List<string> containerNodeNameList, int linkIndex, string fullAssemblyName, string propertyTypeName);
        [OperationContract]
        string RemoveLock(string resourceName, string scriptName, List<string> containerNodeNameList, int linkIndex, int lockIndex);
        [OperationContract]
        string AddLink(string resourceName, string scriptName, List<string> containerNodeNameList, string startNodeName, string endNodeName, string openCriteria);
        [OperationContract]
        string RemoveLink(string resourceName, string scriptName, List<string> containerNodeNameList, int linkIndex);
        [OperationContract]
        string UpdateLinkOpenCriteria(string resourceName, string scriptName, List<string> containerNodeNameList, int linkIndex, string openCriteria);
        [OperationContract]
        string AddNode(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string nodeType);
        [OperationContract]
        string RemoveNode(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName);
        [OperationContract]
        string RenameNode(string resourceName, string scriptName, List<string> containerNodeNameList, string oldName, string newName);
        [OperationContract]
        string UpdateAnimationNode(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string animationName);
        [OperationContract]
        string AddGameDataProperty(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, int gameDataIndex, string propertyName, string propertyValue, string fullAssemblyName, string propertyTypeName);
        [OperationContract]
        string RemoveGameDataProperty(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, int gameDataIndex, string propertyName);
        [OperationContract]
        string UpdateGameDataGameItemName(string gameItemName, string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, int gameDataIndex);
        [OperationContract]
        string UpdateGameData(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, int gameDataIndex, string propertyName, string propertyValue, string fullAssemblyName, string propertyTypeName);
        [OperationContract]
        string AddGameData(string gameItemName, string gameToolName, string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string fullAssemblyName, string gameDataTypeName);
        [OperationContract]
        string RemoveGameData(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, int gameDataIndex);
        [OperationContract]
        string AddResourceItem(string resourceName);
        [OperationContract]
        string RemoveResourceItem(string resourceName);
        [OperationContract]
        string RenameResource(string oldResourceName, string newResourceName);
        [OperationContract]
        string AddNodeScript(string resourceName, string scriptName);
        [OperationContract]
        string RemoveNodeScript(string resourceName, string scriptName);
        [OperationContract]
        string RenameNodeScript(string resourceName, string oldName, string newName);
        [OperationContract]
        string AddGameItem(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string gameItemName);
        [OperationContract]
        string RemoveGameItem(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string gameItemName);
        [OperationContract]
        string RenameGameItem(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string oldGameItemName, string newGameItemName);
        [OperationContract]
        string AddGameTool(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string gameItemName, string gameToolName);
        [OperationContract]
        string RemoveGameTool(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string gameItemName, string gameToolName);
        [OperationContract]
        string AddGameToolDataProperty(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string gameItemName, string gameToolName, string propertyName, string propertyValue, string fullAssemblyName, string propertyTypeName);
        [OperationContract]
        string RemoveGameToolDataProperty(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string gameItemName, string gameToolName, string propertyName);
        [OperationContract]
        string UpdateGameToolDataProperty(string resourceName, string scriptName, List<string> containerNodeNameList, string nodeName, string gameItemName, string gameToolName, string propertyName, string propertyValue, string fullAssemblyName, string propertyTypeName);
        [OperationContract]
        void RequestUpdateForLoadedNodes();
    }
}
